package seismosurfer.gui.panel;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.border.TitledBorder;

import seismosurfer.data.QuakeClientData;
import seismosurfer.data.QuakeMaxMinData;
import seismosurfer.data.constants.ParameterNames;
import seismosurfer.data.constants.QueryNames;
import seismosurfer.data.constants.TopNCategories;
import seismosurfer.gui.DateSelector;
import seismosurfer.gui.GUIConstants;
import seismosurfer.gui.menu.QueryMenu;
import seismosurfer.layer.QuakeLayer;

import com.bbn.openmap.MapBean;
import com.bbn.openmap.gui.OMComponentPanel;

/**
 * The "Top-N Query" panel. 
 *
 */
public class TopNPanel extends OMComponentPanel implements
        PropertyChangeListener, ParameterNames, TopNCategories, QueryNames,
        Serializable, GUIConstants {
    
    private static final long serialVersionUID = -6546774796133221831L;

    // SpinButtons for selecting range of values of the available attributes.
    protected JSpinner LatMin, LatMax, LongMin, LongMax, QuakesCount;

    protected SpinnerNumberModel LatMinSpinModel, LatMaxSpinModel,
            LongMinSpinModel, LongMaxSpinModel, QuakesCountSpinModel;

    private MapBean map = null;

    private QuakeLayer ql = null;

    private double initlatmin;

    private double initlatmax;

    private double initlongmin;

    private double initlongmax;

    // Date selectors consisting of three combo boxes each: year, month, day.
    protected DateSelector TimeMin, TimeMax;

    protected JComboBox queriesList;

    public TopNPanel(ActionListener buttonsListener) {
        super();
        createPanel(buttonsListener);
    }

    protected void createPanel(ActionListener buttonsListener) {

        setLayout(new GridBagLayout());
        setMaximumSize(new Dimension(377, 290));
        setPreferredSize(new Dimension(377, 290));
        setSize(new Dimension(377, 290));

        // Queries Panel
        JPanel queriesPanel = new JPanel(new GridBagLayout());

        add(queriesPanel, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0,
                GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
                        0, 0, 0, 0), 0, 0));

        String choices[] = { STRONG, WEAK, DEEP, SHALLOW, RECENT, OLD };
        queriesList = new JComboBox(choices);

        queriesPanel.add(queriesList, new GridBagConstraints(1, 1, 1, 1, 1.0,
                0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
                new Insets(22, 0, 0, 0), 108, 1));
        JLabel mostLabel = new JLabel("most");
        queriesPanel.add(mostLabel, new GridBagConstraints(0, 1, 1, 1, 0.0,
                0.0, GridBagConstraints.WEST, GridBagConstraints.NONE,
                new Insets(22, 37, 0, 25), 9, 10));

        JLabel earthLabel = new JLabel("earthquakes");
        earthLabel.setHorizontalAlignment(SwingConstants.LEADING);
        earthLabel.setHorizontalTextPosition(SwingConstants.LEADING);
        queriesPanel.add(earthLabel, new GridBagConstraints(2, 1, 1, 1, 0.0,
                0.0, GridBagConstraints.WEST, GridBagConstraints.NONE,
                new Insets(22, 33, 0, 0), 33, 10));

        JLabel findLabel = new JLabel("Find the");
        queriesPanel.add(findLabel, new GridBagConstraints(0, 0, 1, 1, 0.0,
                0.0, GridBagConstraints.WEST, GridBagConstraints.NONE,
                new Insets(10, 37, 0, 0), 19, 11));

        int tempinitval = 10;
        QuakesCountSpinModel = new SpinnerNumberModel(tempinitval, 1, 1000, 1); // (initial
        // value,
        // min,
        // max,
        // step)
        QuakesCount = new JSpinner(QuakesCountSpinModel);
        QuakesCount.setMaximumSize(new Dimension(32767, 32767));
        queriesPanel.add(QuakesCount, new GridBagConstraints(1, 0, 1, 1, 1.0,
                1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
                new Insets(10, 0, 0, 76), 32, 3));

        // Labels Panel
        JPanel labelPanel = new JPanel(new GridLayout());

        add(labelPanel, new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0,
                GridBagConstraints.SOUTH, GridBagConstraints.BOTH, new Insets(
                        0, 0, 0, 0), 319, 4));

        JLabel fromLabel = new JLabel("From");
        fromLabel.setHorizontalAlignment(SwingConstants.CENTER);
        fromLabel.setHorizontalTextPosition(SwingConstants.CENTER);
        fromLabel.setVerticalAlignment(SwingConstants.BOTTOM);
        fromLabel.setVerticalTextPosition(SwingConstants.BOTTOM);
        labelPanel.add(fromLabel, null);

        JLabel toLabel = new JLabel("To");
        toLabel.setHorizontalAlignment(SwingConstants.CENTER);
        toLabel.setHorizontalTextPosition(SwingConstants.CENTER);
        toLabel.setVerticalAlignment(SwingConstants.BOTTOM);
        toLabel.setVerticalTextPosition(SwingConstants.BOTTOM);
        labelPanel.add(toLabel, null);

        // Area Panel
        JPanel areaPanel = new JPanel(new GridBagLayout());
        TitledBorder titledBorder1 = new TitledBorder(BorderFactory
                .createLineBorder(new Color(153, 153, 153), 2), "Area");
        areaPanel.setBorder(titledBorder1);
        areaPanel.setDebugGraphicsOptions(0);

        LatMinSpinModel = new SpinnerNumberModel(initlatmin, -90, 90, 0.1);
        LatMaxSpinModel = new SpinnerNumberModel(initlatmax, -90, 90, 0.1);
        LatMin = new JSpinner(LatMinSpinModel);
        LatMax = new JSpinner(LatMaxSpinModel);

        LongMinSpinModel = new SpinnerNumberModel(initlongmin, -180, 180, 0.1);
        LongMaxSpinModel = new SpinnerNumberModel(initlongmax, -180, 180, 0.1);
        LongMin = new JSpinner(LongMinSpinModel);
        LongMax = new JSpinner(LongMaxSpinModel);

        add(areaPanel, new GridBagConstraints(0, 2, 1, 1, 1.0, 1.0,
                GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
                        0, 0, 0, 0), 0, 2));

        areaPanel.add(LatMax, new GridBagConstraints(2, 0, 1, 1, 1.0, 1.0,
                GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
                        0, 87, 0, 3), 69, 3));
        areaPanel.add(LongMax, new GridBagConstraints(2, 1, 1, 1, 1.0, 1.0,
                GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
                        11, 87, 0, 3), 69, 3));

        JLabel longLabel = new JLabel("Longitude");
        areaPanel.add(longLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0,
                GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(
                        10, 0, 0, 0), 19, 11));
        areaPanel.add(LatMin, new GridBagConstraints(1, 0, 1, 1, 1.0, 1.0,
                GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
                        0, 0, 0, 0), 69, 3));
        areaPanel.add(LongMin, new GridBagConstraints(1, 1, 1, 1, 1.0, 1.0,
                GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
                        10, 0, 0, 0), 69, 4));

        JLabel latLabel = new JLabel("Latitude");
        areaPanel.add(latLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0,
                GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0,
                        0, 0, 0), 29, 11));

        // Time Panel
        JPanel timePanel = new JPanel(new GridBagLayout());
        TitledBorder titledBorder3 = new TitledBorder(BorderFactory
                .createLineBorder(new Color(153, 153, 153), 2), "Time");
        timePanel.setBorder(titledBorder3);

        long tmin = QuakeMaxMinData.getDBMinTime();
        long tmax = QuakeMaxMinData.getDBMaxTime();

        TimeMin = new DateSelector(tmin, tmin, tmax);
        TimeMax = new DateSelector(tmax, tmin, tmax);

        add(timePanel, new GridBagConstraints(0, 3, 1, 1, 1.0, 1.0,
                GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
                        0, 0, 0, 0), 0, -2));

        timePanel.add(TimeMin, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0,
                GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
                new Insets(0, 36, 0, 0), 114, 3));
        timePanel.add(TimeMax, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0,
                GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
                new Insets(0, 38, 0, 1), 114, 3));

        // Buttons Panel

        JPanel buttonsPanel = new JPanel();

        add(buttonsPanel, new GridBagConstraints(0, 4, 1, 1, 1.0, 1.0,
                GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(
                        0, 0, 1, 0), 238, -1));

        JButton okBtn = new JButton("OK");
        okBtn.addActionListener(buttonsListener);
        okBtn.setActionCommand(OK);

        JButton cancelBtn = new JButton("Cancel");
        cancelBtn.addActionListener(buttonsListener);
        cancelBtn.setActionCommand(CANCEL);

        buttonsPanel.add(okBtn, null);
        buttonsPanel.add(cancelBtn, null);

        validate();
    }

    public void sendQueryParameters() {

        Map parameters = new HashMap();

        parameters.put(ORDERBY, (String) queriesList.getSelectedItem());

        System.out.println((String) queriesList.getSelectedItem());

        parameters.put(TIME_MIN, new Long(TimeMin.getValue()));
        parameters.put(TIME_MAX, new Long(TimeMax.getValue()));

        parameters.put(LONG_MIN, (Double) LongMin.getValue());
        parameters.put(LAT_MIN, (Double) LatMin.getValue());

        parameters.put(LONG_MAX, (Double) LongMax.getValue());
        parameters.put(LAT_MAX, (Double) LatMax.getValue());

        parameters.put(ROWNUM, (Integer) (QuakesCount.getValue()));

        parameters.put(SOURCE, getSource());

        if (ql != null) {
            ql.loadQuakeClientData(QueryNames.TOP_N, parameters);
        } else {
            System.out.println("NULL Layer!!!");
        }

    }

    public void updateDialogValues() {
        setCoordinates();
        setValues();
    }

    protected void setCoordinates() {

        if (map != null) {

            initlatmin = ((map.getProjection()).getLowerRight()).getLatitude();
            initlatmax = ((map.getProjection()).getUpperLeft()).getLatitude();
            initlongmin = ((map.getProjection()).getUpperLeft()).getLongitude();
            initlongmax = ((map.getProjection()).getLowerRight())
                    .getLongitude();

            LatMinSpinModel.setValue(new Double(initlatmin));
            LatMaxSpinModel.setValue(new Double(initlatmax));
            LongMinSpinModel.setValue(new Double(initlongmin));
            LongMaxSpinModel.setValue(new Double(initlongmax));
        }
    }

    protected void setValues() {

        int count = 0;
        count = QuakeClientData.getRowCount();

        long tmin = QuakeMaxMinData.getDBMinTime();
        long tmax = QuakeMaxMinData.getDBMaxTime();

        long temptinitval = (count > 0) ? QuakeClientData.getMinTime() : tmin;
        TimeMin.setSelectedDate(temptinitval);

        temptinitval = (count > 0) ? QuakeClientData.getMaxTime() : tmax;
        TimeMax.setSelectedDate(temptinitval);

    }

    public void findAndInit(Object someObj) {

        if (someObj instanceof QuakeLayer) {
            ql = (QuakeLayer) someObj;
        }

        if (someObj instanceof MapBean) {
            map = (MapBean) someObj;
            setCoordinates();
        }

    }

    public void findAndUndo(Object someObj) {

        if (someObj instanceof MapBean && map == someObj) {
            map = null;
        }
    }

    public void propertyChange(PropertyChangeEvent e) {
        if (e.getPropertyName().equalsIgnoreCase(QueryMenu.SourceProperty)) {
            setSource((String) e.getNewValue());
        }
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    private String source;

}
